home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / png / ptot / tiff.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-29  |  17.3 KB  |  652 lines

  1. /*
  2.  * tiff.c
  3.  *
  4.  * TIFF writing routines for PNG-to-TIFF utility.
  5.  *
  6.  **********
  7.  *
  8.  * HISTORY
  9.  *
  10.  * 95-03-10 Created by Lee Daniel Crocker <lee@piclab.com>
  11.  *          <URL:http://www.piclab.com/piclab/index.html>
  12.  */
  13.  
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <math.h>
  18.  
  19. #include "ptot.h"
  20.  
  21. #define DEFINE_ENUMS
  22. #include "errors.h"
  23.  
  24. #define MAX_TAGS 40
  25.  
  26. U16 ASCII_tags[N_KEYWORDS] = {
  27.     TIFF_TAG_Artist, TIFF_TAG_Copyright, TIFF_TAG_Software,
  28.     TIFF_TAG_Model, TIFF_TAG_ImageDescription
  29. };
  30.  
  31. /*
  32.  * Local statics
  33.  */
  34.  
  35. static int write_tag(U16, int, U32, U8 *);
  36. static int get_tag_pos(U16);
  37. static int write_basic_tags(void);
  38. static int write_strips(void);
  39. static int write_extended_tags(void);
  40. static int write_png_data(void);
  41. static int write_ifd(void);
  42. static void align_file_offset(int);
  43.  
  44. static struct _tiff_state {
  45.     IMG_INFO *image;
  46.     FILE *outf;
  47.     int tag_count;
  48.     U16 byte_order;
  49.     U32 file_offset;
  50.     U8 ifd[12 * MAX_TAGS];
  51.     U8 *buf;
  52. } ts;
  53.  
  54. /*
  55.  * Determine what the local byte order is (this is the one we
  56.  * will use for the output TIFF), and verify that we have compiled
  57.  * the correct macros. We're a little more pedantic here than
  58.  * necessary, but if any of this is not exactly right, the whole
  59.  * thing falls apart quietly, so paranoia is justified.
  60.  */
  61.  
  62. int
  63. get_local_byte_order(
  64.     void)
  65. {
  66.     U8 testbuf[4];
  67.     int byte_order;
  68.  
  69.     PUT32(testbuf,0x01020304L);
  70.  
  71.     if (0x01 == *testbuf) {
  72.         byte_order = TIFF_BO_Motorola;
  73.  
  74. #ifndef BIG_ENDIAN
  75.     ASSERT(FALSE);
  76. #endif
  77.         BE_PUT32(testbuf, 0x01020304L);
  78.         if (0x01020304 != GET32(testbuf)) return ERR_BYTE_ORDER;
  79.         LE_PUT32(testbuf, 0x04030201L);
  80.         if (0x01020304 != GET32(testbuf)) return ERR_BYTE_ORDER;
  81.     } else if (0x04 == *testbuf) {
  82.         byte_order = TIFF_BO_Intel;
  83.  
  84. #ifndef LITTLE_ENDIAN
  85.     ASSERT(FALSE);
  86. #endif
  87.         LE_PUT32(testbuf, 0x01020304L);
  88.         if (0x01020304 != GET32(testbuf)) return ERR_BYTE_ORDER;
  89.         BE_PUT32(testbuf, 0x04030201L);
  90.         if (0x01020304 != GET32(testbuf)) return ERR_BYTE_ORDER;
  91.     } else return ERR_BYTE_ORDER;
  92.  
  93.     ASSERT(TIFF_BO_Intel == byte_order || \
  94.       TIFF_BO_Motorola == byte_order);
  95.  
  96.     return byte_order;
  97. }
  98.  
  99. /*
  100.  * Write image specified by IMGINFO structure to TIFF file.
  101.  */
  102.  
  103. int
  104. write_TIFF(
  105.     FILE *outf,
  106.     IMG_INFO *image)
  107. {
  108.     int err;
  109.  
  110.     ASSERT(NULL != outf);
  111.     ASSERT(NULL != image);
  112.     ASSERT(NULL != image->pixel_data_file);
  113.  
  114.     if (NULL == (ts.buf = (U8 *)malloc(IOBUF_SIZE)))
  115.       return ERR_MEMORY;
  116.     ts.outf = outf;
  117.     ts.image = image;
  118.     ts.byte_order = get_local_byte_order();
  119.  
  120.     PUT16(ts.buf, ts.byte_order);
  121.     PUT16(ts.buf+2, TIFF_MagicNumber);
  122.     PUT32(ts.buf+4, 0); /* Will be filled in later */
  123.  
  124.     if (8 != fwrite(ts.buf, 1, 8, outf)) return ERR_WRITE;
  125.     ts.file_offset = 8;
  126.     ts.tag_count = 0;
  127.     memset(ts.ifd, 0, 12 * MAX_TAGS);
  128.  
  129.     if (0 != (err = write_basic_tags())) return err;
  130.     if (0 != (err = write_strips())) return err;
  131.     remove(image->pixel_data_file);
  132.     if (0 != (err = write_extended_tags())) return err;
  133.  
  134.     if (0 != image->png_data_size) {
  135.         ASSERT(NULL != image->png_data_file);
  136.         if (0 != (err = write_png_data())) return err;
  137.         remove(image->png_data_file);
  138.     }
  139.     err = write_ifd();
  140.  
  141.     free(ts.buf);
  142.     return err;
  143. }
  144.  
  145. /*
  146.  * Sizes (in bytes) of the respective TIFF data types
  147.  */
  148. static data_sizes[] = { 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 };
  149.  
  150. #define DIRENT(index,byte) (ts.ifd+12*(index)+(byte))
  151.  
  152. /*
  153.  * Find where to insert the new tag into the sorted IFD
  154.  * by simple linear search.
  155.  */
  156.  
  157. static int
  158. get_tag_pos(
  159.     U16 newtag)
  160. {
  161.     int tag, tagpos, newpos = 0;
  162.  
  163.     while (newpos < ts.tag_count) {
  164.         tag = GET16(DIRENT(newpos,0));
  165.         if (tag > newtag) break;
  166.         ++newpos;
  167.         ASSERT(newpos < MAX_TAGS);
  168.     }
  169.     for (tagpos = ++ts.tag_count; tagpos > newpos; --tagpos) {
  170.         memcpy(DIRENT(tagpos,0), DIRENT(tagpos-1,0), 12);
  171.     }
  172.     PUT16(DIRENT(newpos,0), newtag);
  173.     return newpos;
  174. }
  175.  
  176. static int
  177. write_tag(
  178.     U16 newtag,
  179.     int data_type,
  180.     U32 count,
  181.     U8 *buffer)
  182. {
  183.     U32 data_size;
  184.     int newpos;
  185.  
  186.     ASSERT(ts.tag_count < MAX_TAGS);
  187.     ASSERT(data_type > 0 && data_type <= 12);
  188.     ASSERT(NULL != buffer);
  189.     ASSERT(NULL != ts.outf);
  190.  
  191.     newpos = get_tag_pos(newtag);
  192.     PUT16(DIRENT(newpos,2), data_type);
  193.     PUT32(DIRENT(newpos,4), count);
  194.  
  195.     data_size = count * data_sizes[data_type];
  196.     if (data_size <= 4) {
  197.         memcpy(DIRENT(newpos,8), buffer, 4);
  198.         if (data_size < 4)
  199.            memset(DIRENT(newpos,8+data_size), 0,
  200.              (size_t)(4-data_size));
  201.     } else {
  202.         align_file_offset(2);
  203.         PUT32(DIRENT(newpos,8), ts.file_offset);
  204.         fwrite(buffer, data_sizes[data_type], (size_t)count,
  205.           ts.outf);
  206.         ts.file_offset += count * data_sizes[data_type];
  207.     }
  208.     return 0;
  209. }
  210.  
  211. static int
  212. write_png_data(
  213.     void)
  214. {
  215.     int newpos;
  216.     FILE *inf;
  217.     size_t bytes;
  218.  
  219.     ASSERT(NULL != ts.image->png_data_file);
  220.  
  221.     if (NULL == (inf = fopen(ts.image->png_data_file, "rb")))
  222.       return ERR_READ;
  223.  
  224.     newpos = get_tag_pos(TIFF_TAG_PNGChunks);
  225.     PUT16(DIRENT(newpos,2), TIFF_DT_UNDEFINED);
  226.     PUT32(DIRENT(newpos,4), ts.image->png_data_size);
  227.  
  228.     align_file_offset(2);
  229.     PUT32(DIRENT(newpos,8), ts.file_offset);
  230.     while (0 != ts.image->png_data_size) {
  231.  
  232.         bytes = fread(ts.buf, 1, (size_t)min(IOBUF_SIZE,
  233.           ts.image->png_data_size), inf);
  234.         fwrite(ts.buf, 1, bytes, ts.outf);
  235.         ts.image->png_data_size -= bytes;
  236.         ts.file_offset += bytes;
  237.     }
  238.     fclose(inf);
  239.     return 0;
  240. }
  241.  
  242. #undef DIRENT
  243.  
  244. /*
  245.  * Some data structures must be at even byte offsets in the
  246.  * file. Some must be aligned on 32-bit boundaries. We handle
  247.  * those cases by simply adding pad bytes where needed.
  248.  */
  249.  
  250. static void
  251. align_file_offset(
  252.     int modulus)
  253. {
  254.     ASSERT(modulus > 0 && modulus <= 16);
  255.  
  256.     while (0 != (ts.file_offset % modulus)) {
  257.         putc(0, ts.outf);
  258.         ++ts.file_offset;
  259.     }
  260. }
  261.  
  262. static int
  263. write_basic_tags(
  264.     void)
  265. {
  266.     U16 short_val;
  267.  
  268.     ASSERT(NULL != ts.buf);
  269.     ASSERT(NULL != ts.image);
  270.  
  271.     PUT32(ts.buf, ts.image->width);
  272.     write_tag(TIFF_TAG_ImageWidth, TIFF_DT_LONG, 1, ts.buf);
  273.  
  274.     PUT32(ts.buf, ts.image->height);
  275.     write_tag(TIFF_TAG_ImageLength, TIFF_DT_LONG, 1, ts.buf);
  276.  
  277.     if (ts.image->is_palette) short_val = TIFF_PI_PLTE;
  278.     else if (ts.image->is_color) short_val = TIFF_PI_RGB;
  279.     else short_val = TIFF_PI_GRAY;
  280.     PUT16(ts.buf, short_val);
  281.     write_tag(TIFF_TAG_PhotometricInterpretation,
  282.       TIFF_DT_SHORT, 1, ts.buf);
  283.  
  284.     PUT16(ts.buf, TIFF_CT_NONE);
  285.     write_tag(TIFF_TAG_Compression, TIFF_DT_SHORT, 1, ts.buf);
  286.  
  287.     PUT16(ts.buf, TIFF_PC_CONTIG);
  288.     write_tag(TIFF_TAG_PlanarConfiguration, TIFF_DT_SHORT, 1,
  289.       ts.buf);
  290.  
  291.     PUT16(ts.buf, ts.image->bits_per_sample);
  292.     write_tag(TIFF_TAG_BitsPerSample, TIFF_DT_SHORT, 1, ts.buf);
  293.  
  294.     PUT16(ts.buf, ts.image->samples_per_pixel);
  295.     write_tag(TIFF_TAG_SamplesPerPixel, TIFF_DT_SHORT, 1, ts.buf);
  296.  
  297.     if (ts.image->is_palette) {
  298.         int index, cmap_size;
  299.         U8 *srcp, *redp, *greenp, *bluep;
  300.  
  301.         cmap_size = 1 << ts.image->bits_per_sample;
  302.         if (6 * cmap_size > IOBUF_SIZE) return ERR_WRITE;
  303.         memset(ts.buf, 0, 6 * cmap_size);
  304.  
  305.         srcp = ts.image->palette;
  306.         redp = ts.buf;
  307.         greenp = ts.buf + 2 * cmap_size;
  308.         bluep = ts.buf + 4 * cmap_size;
  309.  
  310.         for (index = 0; index < ts.image->palette_size; ++index) {
  311.             *redp++ = *srcp;
  312.             *redp++ = *srcp++;
  313.             *greenp++ = *srcp;
  314.             *greenp++ = *srcp++;
  315.             *bluep++ = *srcp;
  316.             *bluep++ = *srcp++;
  317.         }
  318.         write_tag(TIFF_TAG_ColorMap, TIFF_DT_SHORT, 3 * cmap_size,
  319.           ts.buf);
  320.     }
  321.     /*
  322.      * Being truly lossless-minded here, we should check for the
  323.      * transparency information in the structure and expand that
  324.      * into a full alpha channel in the TIFF. This is left as an
  325.      * exercise for the reader. :-)
  326.      */
  327.     if (ts.image->has_alpha /* || ts.image->has_trns */) {
  328.         PUT16(ts.buf, TIFF_ES_UNASSOC);
  329.         write_tag(TIFF_TAG_ExtraSamples, TIFF_DT_SHORT, 1, ts.buf);
  330.     }
  331.     return 0;
  332. }
  333.  
  334. static int
  335. write_extended_tags(
  336.     void)
  337. {
  338.     int i;
  339.     U16 tiff_unit;
  340.     U32 xoff, yoff, longside, bias;
  341.  
  342.     tiff_unit = 0xFFFF; /* Not yet assigned */
  343.  
  344.     if (0 != ts.image->xres) {
  345.         if (PNG_MU_None == ts.image->resolution_unit)
  346.           tiff_unit = TIFF_RU_NONE;
  347.         else {
  348.             ASSERT(PNG_MU_Meter == ts.image->resolution_unit);
  349.             tiff_unit = TIFF_RU_CM;
  350.             ts.image->xres /= 100;
  351.             ts.image->yres /= 100;
  352.         }
  353.         PUT16(ts.buf, tiff_unit);
  354.         write_tag(TIFF_TAG_ResolutionUnit, TIFF_DT_SHORT, 1,
  355.           ts.buf);
  356.  
  357.         PUT32(ts.buf, ts.image->xres);
  358.         write_tag(TIFF_TAG_XResolution, TIFF_DT_LONG, 1, ts.buf);
  359.  
  360.         PUT32(ts.buf, ts.image->yres);
  361.         write_tag(TIFF_TAG_YResolution, TIFF_DT_LONG, 1, ts.buf);
  362.     }
  363.     /*
  364.      * TIFF Assumes the same unit for resolution and offset.
  365.      * PNG does not, so we have to do some converting here.
  366.      * Also, TIFF does not apparently allow offsets when there
  367.      * is no resolution unit (or at least doesn't define that
  368.      * case unambiguously). This is one of the very rare cases
  369.      * where TIFF is inadequately specified.
  370.      */
  371.     if (0 != ts.image->xoffset) {
  372.         if (TIFF_RU_NONE != tiff_unit) {
  373.             if (0xFFFF == tiff_unit) {
  374.                 PUT16(ts.buf, tiff_unit = TIFF_RU_CM);
  375.                 write_tag(TIFF_TAG_ResolutionUnit, TIFF_DT_SHORT, 1,
  376.                   ts.buf);
  377.             }
  378.             ASSERT(TIFF_RU_CM == tiff_unit);
  379.  
  380.             xoff = ts.image->xoffset;
  381.             yoff = ts.image->yoffset;
  382.  
  383.             if (PNG_MU_Micrometer != ts.image->offset_unit) {
  384.                 ASSERT(PNG_MU_Pixel == ts.image->offset_unit);
  385.  
  386.                 if (PNG_MU_None == ts.image->resolution_unit) {
  387.                     /*
  388.                      * Assume 72 DPI
  389.                      */
  390.                     xoff = (ts.image->xoffset * 3175) / 9;
  391.                     yoff = (ts.image->yoffset * 3175) / 9;
  392.                 } else {
  393.                     /*
  394.                      * Guard against overflow
  395.                      */
  396.                     longside = max(ts.image->xoffset,
  397.                       ts.image->yoffset);
  398.                     bias = 1;
  399.  
  400.                     while (longside > 2000) {
  401.                         bias *= 2;
  402.                         longside /= 2;
  403.                     }
  404.                     xoff = (ts.image->xoffset * (1000000 / bias)) /
  405.                       (ts.image->xres / bias);
  406.                     yoff = (ts.image->yoffset * (1000000 / bias)) /
  407.                       (ts.image->yres / bias);
  408.                 }
  409.             }
  410.             PUT32(ts.buf, xoff);
  411.             PUT32(ts.buf + 4, 10000L);
  412.             write_tag(TIFF_TAG_XPosition, TIFF_DT_RATIONAL, 1,
  413.               ts.buf);
  414.  
  415.             PUT32(ts.buf, yoff);
  416.             PUT32(ts.buf + 4, 10000L);
  417.             write_tag(TIFF_TAG_YPosition, TIFF_DT_RATIONAL, 1,
  418.               ts.buf);
  419.         }
  420.     }
  421.     /*
  422.      * Map cHRM chunk to WhitePoint and PrimaryChromaticities
  423.      */
  424.     if (0.0 != ts.image->chromaticities[0]) {
  425.         int i;
  426.  
  427.         for (i = 0; i < 2; ++i) {
  428.             PUT32(ts.buf + 8 * i, ts.image->chromaticities[i]);
  429.             PUT32(ts.buf + 8 * i + 4, 100000L);
  430.         }
  431.         write_tag(TIFF_TAG_WhitePoint, TIFF_DT_RATIONAL, 2,
  432.           ts.buf);
  433.  
  434.         for (i = 0; i < 6; ++i) {
  435.             PUT32(ts.buf + 8 * i, ts.image->chromaticities[i+2]);
  436.             PUT32(ts.buf + 8 * i + 4, 100000L);
  437.         }
  438.         write_tag(TIFF_TAG_PrimaryChromaticities, TIFF_DT_RATIONAL,
  439.           6, ts.buf);
  440.     }
  441.     /*
  442.      * ASCII Tags
  443.      */
  444.     for (i = 0; i < N_KEYWORDS; ++i) {
  445.         if (NULL != ts.image->keywords[i]) {
  446.             write_tag(ASCII_tags[i], TIFF_DT_ASCII,
  447.               strlen(ts.image->keywords[i]) + 1,
  448.               ts.image->keywords[i]);
  449.         }
  450.     }
  451.     /*
  452.      * Map gAMA chunk to TransferFunction tag
  453.      */
  454.     if (0.0 != ts.image->source_gamma) {
  455.         U32 count, index;
  456.         double maxval;
  457.  
  458.         count = 1 << ts.image->bits_per_sample;
  459.         if (2 * count > IOBUF_SIZE) return ERR_WRITE;
  460.  
  461.         PUT16(ts.buf, 0);
  462.         maxval = (double)count - 1.0;
  463.  
  464.         for (index = 1; index < count; ++index) {
  465.             PUT16(ts.buf + 2 * index,
  466.               (U16)floor(0.5 + 65535 * pow((double)index / maxval,
  467.               1.0 / ts.image->source_gamma)));
  468.         }
  469.         write_tag(TIFF_TAG_TransferFunction, TIFF_DT_SHORT,
  470.           count, ts.buf);
  471.     }
  472.     return 0;
  473. }
  474.  
  475. static int
  476. write_ifd(
  477.     void)
  478. {
  479.     int err;
  480.  
  481.     ASSERT(NULL != ts.buf);
  482.     ASSERT(NULL != ts.outf);
  483.     ASSERT(ts.tag_count <= MAX_TAGS);
  484.  
  485.     align_file_offset(2);
  486.     if (ts.file_offset == (U32)ftell(ts.outf)) err = 0;
  487.     else err = ERR_WRITE;
  488.  
  489.     PUT16(ts.buf, ts.tag_count);
  490.     fwrite(ts.buf, 2, 1, ts.outf);
  491.     fwrite(ts.ifd, 12, ts.tag_count, ts.outf);
  492.     PUT32(ts.buf, 0L);
  493.     fwrite(ts.buf, 4, 1, ts.outf);
  494.  
  495.     PUT32(ts.buf, ts.file_offset);
  496.     fseek(ts.outf, 4L, SEEK_SET);
  497.     fwrite(ts.buf, 1, 4, ts.outf);
  498.  
  499.     return 0;
  500. }
  501.  
  502. /*
  503.  * Write out the actual pixel data into approximately 8k strips
  504.  * (larger if needed to fit the StripOffsets data into one I/O
  505.  * buffer) and write the related tags.
  506.  */
  507.  
  508. #define BPS (ts.image->bits_per_sample)
  509. #define SPP (ts.image->samples_per_pixel)
  510. #define OKW(x) ((x)<ts.image->width)
  511.  
  512. static int
  513. write_strips(
  514.     void)
  515. {
  516.     size_t line_size, strip_size;
  517.     U32 strip, total_strips, rows_per_strip;
  518.     U8 *line_buf;
  519.     FILE *inf;
  520.  
  521.     line_size = new_line_size(ts.image, 0, 1);
  522.     if (line_size > 4096) {
  523.         rows_per_strip = 1;
  524.     } else {
  525.         rows_per_strip = 8192 / line_size;
  526.     }
  527.     ASSERT(0 != rows_per_strip);
  528.  
  529.     do {
  530.         strip_size = rows_per_strip * line_size;
  531.         total_strips = (ts.image->height + (rows_per_strip - 1)) /
  532.           rows_per_strip;
  533.         rows_per_strip *= 2;
  534.     } while (4 * total_strips > IOBUF_SIZE);
  535.     rows_per_strip /= 2;
  536.  
  537.     PUT32(ts.buf, rows_per_strip);
  538.     write_tag(TIFF_TAG_RowsPerStrip, TIFF_DT_LONG, 1, ts.buf);
  539.  
  540.     for (strip = 0; strip < total_strips; ++strip) {
  541.         PUT32(ts.buf + 4 * strip, strip_size);
  542.     }
  543.     write_tag(TIFF_TAG_StripByteCounts, TIFF_DT_LONG,
  544.       total_strips, ts.buf);
  545.  
  546.     align_file_offset(2);
  547.     if (0 != (strip_size & 1)) ++strip_size;
  548.  
  549.     for (strip = 0; strip < total_strips; ++strip) {
  550.         PUT32(ts.buf + 4 * strip, ts.file_offset +
  551.           4 * total_strips + strip * strip_size);
  552.     }
  553.     write_tag(TIFF_TAG_StripOffsets, TIFF_DT_LONG,
  554.       total_strips, ts.buf);
  555.     /*
  556.      * Write the strip data from the pixel data file.
  557.      */
  558.     if (NULL == (line_buf = (U8 *)malloc(line_size)))
  559.       return ERR_MEMORY;
  560.  
  561.     ASSERT(NULL != ts.image->pixel_data_file);
  562.     if (NULL == (inf = fopen(ts.image->pixel_data_file, "rb"))) {
  563.         free(line_buf);
  564.         return ERR_READ;
  565.     }
  566.     for (strip = 0; strip < total_strips; ++strip) {
  567.         U32 row, col, scanline;
  568.  
  569.         scanline = 0;
  570.         align_file_offset(2);
  571.  
  572.         for (row = 0; row < rows_per_strip; ++row) {
  573.             int bit, byte, step, sample;
  574.             U16 word;
  575.             U8 *lp;
  576.  
  577.             lp = line_buf;
  578.             if (BPS < 8) step = 8 / BPS;
  579.             else step = 1;
  580.  
  581.             for (col = 0; col < ts.image->width; col += step) {
  582.                 switch (BPS) {
  583.                 case 1:
  584.                     ASSERT(1 == SPP);
  585.  
  586.                     *lp = getc(inf) & 0x80;
  587.                     for (bit = 1; bit < 8; ++bit) {
  588.                         if (!OKW(col+bit)) break;
  589.                         byte = getc(inf);
  590.                         if (0 != (byte & 0x80)) {
  591.                             *lp |= (1 << (7 - bit));
  592.                         }
  593.                     }
  594.                     ++lp;
  595.                     break;
  596.                 case 2:
  597.                     ASSERT(1 == SPP);
  598.  
  599.                     *lp = getc(inf) & 0xC0;
  600.                     if OKW(col+1) *lp |= ((getc(inf) >> 2) & 0x30);
  601.                     if OKW(col+2) *lp |= ((getc(inf) >> 4) & 0x0C);
  602.                     if OKW(col+3) *lp |= ((getc(inf) >> 6) & 0x03);
  603.                     ++lp;
  604.                     break;
  605.                 case 4:
  606.                     ASSERT(1 == SPP);
  607.  
  608.                     *lp = getc(inf) & 0xF0;
  609.                     if OKW(col+1) *lp |= ((getc(inf) >> 4) & 0x0F);
  610.                     ++lp;
  611.                     break;
  612.                 case 8:
  613.                     for (sample = 0; sample < SPP; ++sample) {
  614.                         *lp++ = (0xFF & getc(inf));
  615.                     }
  616.                     break;
  617.                 case 16:
  618.                     for (sample = 0; sample < SPP; ++sample) {
  619.                          word = ((getc(inf) << 8) & 0xFF00);
  620.                          word |= (0xFF & getc(inf));
  621.                          PUT16(lp, word);
  622.                          lp += 2;
  623.                     }
  624.                     break;
  625.                 default:
  626.                     ASSERT(FALSE);
  627.                 }
  628.             }
  629.             ASSERT(lp - line_buf == line_size);
  630.             if (line_size != fwrite(line_buf, 1, line_size, ts.outf)) {
  631.                 fclose(inf);
  632.                 free(line_buf);
  633.                 return ERR_WRITE;
  634.             }
  635.             ts.file_offset += line_size;
  636.             if (++scanline >= ts.image->height) break;
  637.         }
  638.     }
  639.     fclose(inf);
  640.     free(line_buf);
  641.     return 0;
  642. }
  643.  
  644. #undef SPP
  645. #undef BPS
  646. #undef OKW
  647.  
  648. /*
  649.  * End of TIFF.C
  650.  */
  651.  
  652.